package com.zp.self.module.level_4_算法练习.算法.多线程;
import org.junit.Test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author By ZengPeng
 */
public class 力扣_1114_按序打印 {
    @Test
    public void main() throws InterruptedException {
        
        Solution solution = new 力扣_1114_按序打印().new Solution();
        solution.threadTest(new int[]{3,1,2});
    }

    /**
     题目：给你一个类：
         public class Foo {
         public void first() { print("first"); }
         public void second() { print("second"); }
         public void third() { print("third"); }
         }
         三个不同的线程 A、B、C 将会共用一个 Foo 实例。
         线程 A 将会调用 first() 方法
         线程 B 将会调用 second() 方法
         线程 C 将会调用 third() 方法
         请设计修改程序，以确保 second() 方法在 first() 方法之后被执行，third() 方法在 second() 方法之后被执行。

         提示：
         尽管输入中的数字似乎暗示了顺序，但是我们并不保证线程在操作系统中的调度顺序。
         你看到的输入格式主要是为了确保测试的全面性。

         示例 1：
         输入：nums = [1,2,3]
         输出："firstsecondthird"
         解释：
         有三个线程会被异步启动。输入 [1,2,3] 表示线程 A 将会调用 first() 方法，线程 B 将会调用 second() 方法，线程 C 将会调用 third() 方法。正确的输出是 "firstsecondthird"。

         示例 2：
         输入：nums = [1,3,2]
         输出："firstsecondthird"
         解释：
         输入 [1,3,2] 表示线程 A 将会调用 first() 方法，线程 B 将会调用 third() 方法，线程 C 将会调用 second() 方法。正确的输出是 "firstsecondthird"。

     分析：【RP 💖💖💖💖】
        1.多线程：Condition + 状态标记，没有状态标记将无法得知线程2是否需要搁置。如下：
                情况一、1.如果 线程1 抢先获取到锁，执行完后唤醒condition2中的线程，
                      2.但现在condition2 中没有线程2，因为线程2未获得锁，未加入condition2中进行搁置
                      3.线程2获取到锁，不知道是否应该搁置，如果搁置了，线程2可能进入假死状态.
                所以这里必须得有个标记。告诉线程2：线程1是否已经执行过了。 是：执行，否：释放锁，搁置等待



     边界值 & 注意点：
        1.
     **/
//leetcode submit region begin(Prohibit modification and deletion)
class Foo {
        private  ReentrantLock lock = new ReentrantLock();
        private Condition condition1 = lock.newCondition();
        private Condition condition2 = lock.newCondition();
        private Condition condition3 = lock.newCondition();
        volatile int state=0;
    public Foo() {

    }


    public void first(Runnable printFirst) throws InterruptedException {
        lock.lock();
        // printFirst.run() outputs "first". Do not change or remove this line.
        try {
            printFirst.run();
            state=1;
            condition2.signal();
        } finally {
            lock.unlock();
        }
    }

    public void second(Runnable printSecond) throws InterruptedException {
        lock.lock();
        try {
            if(state!=1)
                condition2.await();
            // printSecond.run() outputs "second". Do not change or remove this line.
            printSecond.run();
            state=2;
            condition3.signal();
        } finally {
            lock.unlock();
        }
    }

    public void third(Runnable printThird) throws InterruptedException {
        lock.lock();
        try {
            if(state!=2)
            condition3.await();
            // printThird.run() outputs "third". Do not change or remove this line.
            printThird.run();
        } finally {
            lock.unlock();
        }
    }
}
class Solution {
    public void threadTest(int[] order)throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        Foo foo = new Foo();
        new Thread(() -> {
            try {
                if(order[0]==1){
                    foo.first(() -> System.out.print("first"));
                }else if(order[0]==2){
                    foo.second(() -> System.out.print("second"));
                }else
                    foo.third(() -> System.out.print("third"));
            } catch (Exception e) {
                e.printStackTrace();
            }
            countDownLatch.countDown();
        },"线程A").start();


        new Thread(() -> {
            try {
                if(order[1]==1){
                    foo.first(() -> System.out.print("first"));
                }else if(order[1]==2){
                    foo.second(() -> System.out.print("second"));
                }else
                    foo.third(() -> System.out.print("third"));

            } catch (Exception e) {
                e.printStackTrace();
            }
            countDownLatch.countDown();
        },"线程B").start();

        new Thread(() -> {
            try {
                if(order[2]==1){
                    foo.first(() -> System.out.print("first"));
                }else if(order[2]==2){
                    foo.second(() -> System.out.print("second"));
                }else
                    foo.third(() -> System.out.print("third"));

            } catch (Exception e) {
                e.printStackTrace();
            }
            countDownLatch.countDown();
        },"线程C").start();


        countDownLatch.await();
    }
}
//leetcode submit region end(Prohibit modification and deletion)

}